use std::io;
use std::sync::Arc;

use thiserror::Error;

use crate::svc;

macro_rules! services {
    {
        $(($name:ident, $svc_trait:ty)),*
    } => {
        #[derive(Clone)]
        pub enum Service {
            $(
                $name(Arc<dyn ($svc_trait)>)
            ),*
        }

        #[derive(Copy, Clone, Eq, PartialEq, Debug)]
        pub enum ServiceTy {
            $($name,)*
        }

        impl Service {
            pub fn ty(&self) -> ServiceTy {
                match self {
                    $(Self::$name(_) => ServiceTy::$name,)*
                }
            }
        }

        $(
            impl From<Arc<dyn ($svc_trait)>> for Service {
                fn from(s: Arc<dyn ($svc_trait)>) -> Self {
                    Self::$name(s)
                }
            }
        )*
    }
}

services! {
    (P2P, svc::p2p::P2PService),
    (EmbWallet, svc::emb_wallet::EmbWalletService)
}

#[derive(Debug, Error)]
pub enum SvcError {
    #[error("unspecified: {0}")]
    Unspecified(String),

    #[error("io: {0}")]
    Io(io::Error),
}
